﻿using Joy.Erp.BasicArchives.Core;
using System;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;

namespace Joy.Erp.BasicArchives.SerialNumbers
{
    public class SerialNumberManager : ISerialNumberManager, ISingletonDependency
    {
        protected ISerialNumberRepository SerialNumberRepository { get; }

        public SerialNumberManager(ISerialNumberRepository serialNumberRepository)
        {
            SerialNumberRepository = serialNumberRepository;
        }

        public async Task<long> NextAsync(string key, long start = 1, long stride = 1, ResetInterval resetInterval = ResetInterval.None)
        {
            var serialNumber = await SerialNumberRepository.FirstOrDefaultAsync(x => x.Key == key);
            if (serialNumber == null)
            {
                serialNumber = new SerialNumber { Key = key, Value = start };
                await SerialNumberRepository.InsertAsync(serialNumber);
            }
            else if (resetInterval == ResetInterval.None)
            {
                serialNumber.Value = Math.Max(start, serialNumber.Value + stride);
                await SerialNumberRepository.UpdateAsync(serialNumber);
            }
            else
            {
                switch (resetInterval)
                {
                    case ResetInterval.Year:
                        serialNumber.Value = serialNumber.IsCurrentYear() ? Math.Max(start, serialNumber.Value + stride) : start;
                        await SerialNumberRepository.UpdateAsync(serialNumber);
                        break;

                    case ResetInterval.Month:
                        serialNumber.Value = serialNumber.IsCurrentMonth() ? Math.Max(start, serialNumber.Value + stride) : start;
                        await SerialNumberRepository.UpdateAsync(serialNumber);
                        break;

                    case ResetInterval.Day:
                        serialNumber.Value = serialNumber.IsCurrentDay() ? Math.Max(start, serialNumber.Value + stride) : start;
                        await SerialNumberRepository.UpdateAsync(serialNumber);
                        break;

                    case ResetInterval.Hour:
                        serialNumber.Value = serialNumber.IsCurrentHour() ? Math.Max(start, serialNumber.Value + stride) : start;
                        await SerialNumberRepository.UpdateAsync(serialNumber);
                        break;

                    case ResetInterval.Minutes:
                        serialNumber.Value = serialNumber.IsCurrentMinute() ? Math.Max(start, serialNumber.Value + stride) : start;
                        await SerialNumberRepository.UpdateAsync(serialNumber);
                        break;

                    case ResetInterval.Seconds:
                        serialNumber.Value = serialNumber.IsCurrentSecond() ? Math.Max(start, serialNumber.Value + stride) : start;
                        await SerialNumberRepository.UpdateAsync(serialNumber);
                        break;

                    default:
                        serialNumber.Value = Math.Max(start, serialNumber.Value + stride);
                        await SerialNumberRepository.UpdateAsync(serialNumber);
                        break;
                }
            }

            return serialNumber.Value;
        }

        public async Task<long> RestartAsync(string key, long start = 1)
        {
            var serialNumber = await SerialNumberRepository.FirstOrDefaultAsync(x => x.Key == key);
            if (serialNumber == null)
            {
                serialNumber = new SerialNumber { Key = key, Value = start };
                await SerialNumberRepository.InsertAsync(serialNumber);
            }
            else
            {
                serialNumber.Value = start;
                await SerialNumberRepository.UpdateAsync(serialNumber);
            }

            return serialNumber.Value;
        }
    }
}
